use redis::Commands;
use std::env;
use std::process::exit;
use chrono::{Local, NaiveDateTime, TimeZone};
use serde_json::Value;

/**
2025年3月19日17:54:31
根据stime清理过期的field
 */
fn main() -> redis::RedisResult<()> {
    let args: Vec<String> = env::args().collect();
    if args.len() != 6 {
        println!("Usage: {} redis://:OneThing_redis@api-redis.data.onething.internal:6379 key_pattern field1_pattern,field2_pattern,... max_duration(s) del/print", args[0]);
        exit(1);
    }

    let url = args[1].clone();
    let key_pattern = args[2].clone();
    let field_pattern_str = args[3].clone();
    let max_duration = args[4].parse::<i64>().unwrap_or_else(|_| panic!("Cannot parse {} as a number", args[4]));
    let action = args[5].clone();
    let field_patterns:Vec<&str> = field_pattern_str.split(",").collect::<Vec<&str>>();


    // 使用？等价于unwrap() ,相当于把异常抛出去,当前函数必须有返回值
    let client = redis::Client::open(url.as_str())?;
    let mut scan_conn = client.get_connection()?;
    let mut conn = client.get_connection()?;

    let iter: redis::Iter<String> = redis::cmd("SCAN")
        .cursor_arg(0)
        .clone()
        .iter(&mut scan_conn)?;

    let stime_format = "%Y-%m-%d %H:%M:%S";
    for key in iter {
        if key.contains(key_pattern.as_str()) {
            let fields: Vec<String> = conn.hkeys(&key).unwrap_or_else(|_e| return vec![]);

            let fields: Vec<String> = fields
                .iter()
                .filter(|s| {
                    for x in &field_patterns {
                        if s.contains(x) {
                            return true;
                        }
                    }
                    return false;

                })
                .cloned()
                .collect();

            for i in 0..fields.len() {
                let val: String = conn.hget(&key, fields.get(i)).unwrap_or_else(|_e| {
                    return "".to_string();
                });

                let stime_str = get_stime_str(&val);
                if stime_str == None {
                    println!("Error removing field {}_{}: {}", key,fields.get(i).unwrap().as_str(), val);
                    continue;
                }
                let dt = NaiveDateTime::parse_from_str(stime_str.unwrap().as_str(), stime_format)
                    .unwrap_or_else(|_e| {
                        return Local::now().naive_local();
                    });
                let target_time = Local.from_local_datetime(&dt).unwrap();
                let current_time = Local::now();
                let duration = current_time.timestamp() - target_time.timestamp();
                if duration > max_duration {
                    if action == "del" {
                        conn.hdel(&key, fields.get(i)).unwrap_or_else(|e| {
                            println!("Error removing field {}_{}: {}", key,fields.get(i).unwrap().as_str(), e);
                        })
                    }
                    println!("{} {} {}", &key, fields.get(i).unwrap().as_str(), val);
                }

            }
        }
    }

    Ok(())
}


fn get_stime_str(val: &str) -> Option<String> {

    if val.len() > 31 {
        let stime_str = &val[10..28];
        Some(stime_str.to_string())
    } else {
        None
    }
}

/**
error[E0515]: cannot return value referencing local variable `json_val`
  --> src\server:98:12
   |
97 |     let aa = json_val.get("stime").unwrap().as_str().unwrap().clone();
   |              -------- `json_val` is borrowed here
98 |     return aa
   |            ^^ returns a value referencing data owned by the current function
*/
// fn get_stime_timestamp_json(val: &str) -> &str {
//
//     // 替换\N 避免json转换失败
//     let val = val.replace("\\N", "");
//     let json_val: Value = serde_json::from_str(val.as_str()).unwrap_or_else(|e| {
//         println!("meet error: {}", val);
//         println!("{}", e);
//         return Value::default();
//     });
//     let aa = json_val.get("stime").unwrap().as_str().unwrap().clone();
//     return aa
// }

// 不出现 "is never used" 警告
#[allow(dead_code)]
fn get_stime_timestamp_json(val: &str) -> String {

    // 替换\N 避免json转换失败
    let val = val.replace("\\N", "");
    let json_val: Value = serde_json::from_str(val.as_str()).unwrap_or_else(|e| {
        println!("meet error: {}", val);
        println!("{}", e);
        return Value::default();
    });
    let aa = json_val.get("stime").and_then(|v|v.as_str()   ).unwrap_or("").to_string();
    return aa
}